﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using Dapper;

namespace AmoExtensions
{
    /*
     * SSAS Partition Manager
     * https://ssaspartitionmanager.codeplex.com/
     * Written by Dr. John Tunnicliffe of Decision Analytics, April 2015
     * eMail: john@decision-analytics.co.uk 
     * http://www.decision-analytics.co.uk/
     * https://www.linkedin.com/in/drjohntunnicliffe
     */

    /// <summary>
    /// Runs T-SQL queries against the SQL Server relational database using Dapper
    /// </summary>
    public class PartitionRepository : IPartitionRepository 
    {
        /// <summary>
        /// The connection string to the database containing the spm.OlapPartitions view
        /// </summary>
        private readonly string connectionString;

        /// <summary>
        /// The SQL query string to list the 
        /// </summary>
        private readonly string sqlListServers;
        private readonly string sqlListPartitions;

        /// <summary>
        /// Initializes a new instance of the PartitionRepository class.
        /// </summary>
        /// <param name="connectionString">The connection string to the database containing the config.OlapPartitions view.</param>#
        /// <exception cref="System.ArgumentNullException">If any arguments are null.</exception>
        public PartitionRepository(string connectionString, string sqlListServers, string sqlListPartitions)
        {
            if (connectionString.IsNullOrEmptyOrWhitespace()) throw new ArgumentNullException("connectionString");
            if (sqlListServers.IsNullOrEmptyOrWhitespace()) throw new ArgumentNullException("sqlListServers");
            if (sqlListPartitions.IsNullOrEmptyOrWhitespace()) throw new ArgumentNullException("sqlListPartitions");

            this.connectionString = connectionString;
            this.sqlListServers = sqlListServers;
            this.sqlListPartitions = sqlListPartitions;
        }

        /// <summary>
        /// Obtains the name of the OLAP server we going to connect to which hosts all the OLAP databases
        /// </summary>
        /// <returns>ServerName</returns>
        public string SsasServerName(string SsasServerType)
        {
            return QueryDynamic(this.sqlListServers).Cast<dynamic>().Where(x => x.SsasServerType == SsasServerType).FirstOrDefault().SsasServerName;
        }

        #region GetListOfPartitions
        /// <summary>
        /// Gets the list of partitions we need to create from the spm.SsasPartitions view in the SQL database
        /// </summary>
        /// <param name="partitionRepository">A PartitionRepository object which contains the list of partitions we need to create</param>
        /// <returns>The count of partitions returned by the query</returns>
        public IEnumerable<IPartition> GetListOfPartitions(IAmoServer server)
        {
            if (server == null)
            {
                throw new ArgumentNullException("server");
            }
            
            // Obtain the list of partitions we need in the cube from the SQL view
            // Note we call the .ToList method as we want to force population of the list immediately
            IEnumerable<IPartition> ListOfPartitions = this.QueryDynamic(sqlListPartitions)   // returns a list of all partitions that should be in all the SSAS databases on the server (both Multidimensional and Tabular)
                .Select(x => Partition.FromDynamic(server, x))
                .Cast<Partition>()  // cast the dynamic object into a partition object
                .Where(x => x.ModelType == server.ServerMode)  // this selects only the partitions relevant to the server type we are connected to (either Multidimensional and Tabular)
                .ToList(); // convert everything to a list object

            return ListOfPartitions;
        }
        #endregion

        /// <summary>
        /// Helper method to execute a query and return the results using Dapper library
        /// </summary>
        /// <param name="sql">The SQL query to execute.</param>
        /// <returns>
        /// A sequence of dynamic objects representing the result set.
        /// </returns>
        private IEnumerable<dynamic> QueryDynamic(string sql)
        {
            using (var connection = new SqlConnection(this.connectionString))
            {
                connection.Open();
                return connection.Query(sql);
            }
        }
    }
}
